package com.ycg.vue.modules.user.service.impl;

import com.ycg.vue.Entity.FileEntity;
import com.ycg.vue.Entity.OperationLogEntity;
import com.ycg.vue.Entity.UserEntity;
import com.ycg.vue.Entity.Dto.UserDto;
import com.ycg.vue.Entity.Vo.UserVo;
import com.ycg.vue.Enum.LogEnum;
import com.ycg.vue.Enum.MinIOPathEnum;
import com.ycg.vue.constant.Constant;
import com.ycg.vue.context.ThreadLocalContext;
import com.ycg.vue.modules.system.mapper.SystemMapper;
import com.ycg.vue.modules.user.mapper.FileMapper;
import com.ycg.vue.modules.user.mapper.UserMapper;
import com.ycg.vue.result.Result;
import com.ycg.vue.modules.user.service.UserService;
import com.ycg.vue.utils.IpAddressUtils;
import com.ycg.vue.utils.JwtUtils;
import com.ycg.vue.utils.MinioUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author jink
 * @Date 2024/1/5
 */
@Transactional
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private FileMapper fileMapper;

    @Resource
    private MinioUtils minioUtils;

    @Resource
    private SystemMapper systemMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private static final Long DELAYED_TIME = 3600L;

    @Override
    public Result login(UserDto userDto, HttpServletRequest request) {
        try {
            String username = userDto.getUsername();
            String password = DigestUtils.md5DigestAsHex(userDto.getPassword().getBytes());
            if (userMapper.selectByUserName(username) == 0) {
                return Result.error(Constant.USER_NOT_EXIST);
            }
            if (userMapper.selectByPassword(username, password) == 0) {
                return Result.error(Constant.PASSWORD_ERROR);
            }
            UserEntity user = userMapper.login(username, password);
            String ip = IpAddressUtils.getIpAddress(request);
            if (!Objects.isNull(user)) {
                Map<String, Object> claims = new HashMap<>();
                claims.put("id", user.getId());
                claims.put("username", user.getUsername());
                claims.put("ip", ip);
                String token = JwtUtils.generateJwt(claims);
                redisTemplate.opsForValue().set(userDto.getFingerprint(), token, userDto.getDays(), TimeUnit.DAYS);
                UserVo userVo = UserVo.builder().realName(user.getRealName()).identity(user.getIdentity()).headImage(user.getHeadImage()).build();
                Map<String, Object> result = new HashMap<>();
                result.put("token", token);
                result.put("user", userVo);
                ThreadLocalContext.setUserId(user.getId());
                ThreadLocalContext.setUserName(user.getUsername());
                ThreadLocalContext.setIp(ip);
                systemMapper.insertLog(OperationLogEntity.builder().type(LogEnum.LOGIN.getName()).operation(LogEnum.LOGIN.getName()).build());
                return Result.success(result);
            }
            return Result.error(Constant.USER_STATUS_ERROR);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(Constant.LOGIN_ERROR);
        }
    }

    @Override
    public Result register(UserDto user) {
        if (userMapper.selectByUserName(user.getUsername()) > 0) {
            return Result.error(Constant.USER_EXIST);
        }
        if(user.getCode().isEmpty()){
            return Result.error(Constant.CAPTCHA_ERROR);
        }else{
            String o = Objects.requireNonNull(redisTemplate.opsForValue().get(user.getEmail())).toString().trim();
            if(o.isEmpty() || !o.equals(user.getCode())){
                return Result.error(Constant.CAPTCHA_ERROR);
            }
        }
        UserEntity userEntity = new UserEntity();
        try {
            BeanUtils.copyProperties(userEntity,user);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        userEntity.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        userMapper.register(userEntity);
        return Result.success(Constant.REGISTER_SUCCESS, null);
    }

    @Override
    public Result upload(MultipartFile file) {
        return Result.success(fileMapper.selectByGroupId(minioUtils.upload(file, MinIOPathEnum.HEAD_IMG)));
    }

    @Override
    public Result getUser() {
        String userId = ThreadLocalContext.getUserId();
        if (Objects.isNull(userId)) return Result.error(Constant.USER_NOT_LOGIN);
        UserEntity user = userMapper.selectByGroupId(userId);
        if (Objects.isNull(user)) return Result.error(Constant.USER_NOT_EXIST);
        return Result.success(user);
    }

    @Override
    public Result updateHeadImage(MultipartFile file) {
        FileEntity fileEntity = fileMapper.selectByGroupId(minioUtils.upload(file, MinIOPathEnum.HEAD_IMG));
        String userId = ThreadLocalContext.getUserId();
        UserEntity user = userMapper.selectByUserId(userId);
        if(userId == null) return Result.error(Constant.USER_STATUS_ERROR);
        if(file.isEmpty()) return Result.error(Constant.IMAGE_UPLOAD_ERROR);
        userMapper.updateHeadImage(fileEntity.getId(), userId);
        return Result.success();
    }

    @Override
    public Result updatePassword(Map<String, String> pwd) {
        String userId = ThreadLocalContext.getUserId();
        if (userId == null || !userId.equals(pwd.get("id") == null ? "" : pwd.get("id")))
            return Result.error(Constant.USER_STATUS_ERROR);
        UserEntity user = userMapper.selectByUserId(userId);
        if (user == null) return Result.error(Constant.USER_NOT_EXIST);
        String old = pwd.get("old") == null ? "" : DigestUtils.md5DigestAsHex(pwd.get("old").getBytes());
        if (!user.getPassword().equals(old)) return Result.error(Constant.OLD_PASSWORD_ERROR);
        String newPwd = pwd.get(("new"));
        if(newPwd == null) return Result.error(Constant.PASSWORD_ERROR);
        userMapper.updatePassword(DigestUtils.md5DigestAsHex(newPwd.getBytes()), userId);
        return Result.success();
    }

    @Override
    public Result updateHeadImgByMaterial(Map<String, String> map) {
        if(map.get("id") == null) return Result.error(Constant.USER_STATUS_ERROR);
        UserEntity user = userMapper.selectByUserId(map.get("id"));
        if (user == null) return Result.error(Constant.USER_NOT_EXIST);
        if(map.get("groupId") == null) return Result.error(Constant.MATERIAL_STATUS_ERROR);
        userMapper.updateHeadImage(map.get("groupId"), map.get("id"));
        return Result.success();
    }
}
